﻿using System;
using System.Threading;
using System.Runtime.InteropServices;
using Microsoft.WindowsCE.Forms;
using LC;

namespace Scan
{
    public delegate void GetBarcodHandler(IntPtr wParam);

    public class BarcodeManager
    {
        private NLog.Logger logger = NLog.LogManager.GetLogger("BarcodeManagement");

        /// <summary>
        /// 事件数
        /// </summary>
        private const uint eventCount = 3;

        /// <summary>
        /// 扫描事件
        /// </summary>
        private IntPtr[] hEvents = new IntPtr[eventCount];

        /// <summary>
        /// 消息接收窗体
        /// </summary>
        private ScanMsgWindow msgWindow;

        /// <summary>
        /// 接收条码
        /// </summary>
        public event GetBarcodHandler OnGetBarcode = null;

        /// <summary>
        /// 是否正在连续扫描
        /// </summary>
        private bool m_IsScanning = false;
        public bool IsScanning
        {
            get { return m_IsScanning; }
        }

        public BarcodeManager()
        {
            for (int i = 0; i < eventCount; i++)
            {
                hEvents[i] = Win32.CreateEvent(IntPtr.Zero, false, false, null);
            }
        }

        ~BarcodeManager()
        {
            for (int i = 0; i < eventCount; i++)
            {
                Win32.CloseHandle(hEvents[i]);
            }
        }

        /// <summary>
        /// 开始
        /// </summary>
        /// <returns></returns>
        public bool Start()
        {
            logger.Info("Start barcode thread.");

            msgWindow = new ScanMsgWindow(this);
            Scanner.RegisterScannerMessage(this.msgWindow.Hwnd, Scanner.WM_SCANMSG);
            Thread barcodeThread = new Thread(new ThreadStart(BarcodeThreadProc));
            barcodeThread.Start();
            
            return Scanner.EnableScanner();
        }

        /// <summary>
        /// 关闭扫描头以及结束 barcodeThreadProc
        /// </summary>
        public void Stop()
        {
            if (Scanner.IsScannerEnabled())
            {
                Scanner.DisableScanner();
            }
            OnGetBarcode = null;
            Win32.EventModify(hEvents[0], Win32.EVENT_SET);
        }

        /// <summary>
        /// 开启持续扫描
        /// 或停止持续扫描
        /// </summary>
        public void ContinuousOrStopScanning()
        {
            if (!m_IsScanning)
            {
                m_IsScanning = true;
                Scanner.SetTriggerMode((int)LC.Scanner.TriggerMode.Continuous);
            }
            else
            {
                m_IsScanning = false;
                Scanner.SetTriggerMode((int)LC.Scanner.TriggerMode.Normal);
            }
        }

        /// <summary>
        /// 上一次扫描是否已经停止
        /// </summary>
        /// <returns></returns>
        public bool IsStopScan()
        {
            return (Win32.WaitForSingleObject(hEvents[1], 0) == 0);
        }

        private void BarcodeThreadProc()
        {
            while (true)
            {
                uint evt = Win32.WaitForMultipleObjects(eventCount, hEvents, false, Win32.INFINITE);

                switch (evt)
                {
                    case 0:
                        logger.Info("Stop barcode thread");
                        return;
                    case 1:
                        {
                            Win32.EventModify(hEvents[2], Win32.EVENT_RESET);
                            Scanner.StartScan();
                            Win32.WaitForSingleObject(hEvents[2], 2000);
                            Scanner.StopScan();
                            Win32.EventModify(hEvents[1], Win32.EVENT_RESET);
                        }
                        break;
                }
            }
        }

        /// <summary>
        /// 获取条码
        /// </summary>
        /// <param name="wParam"></param>
        public void GetBarcode(IntPtr wParam)
        {
            if (OnGetBarcode != null)
            {
                OnGetBarcode(wParam);
            }
        }

        public void Send(ScanStatus scanType)
        {
            Win32.EventModify(hEvents[(uint)scanType], Win32.EVENT_SET);
        }
    }

    public class ScanMsgWindow : MessageWindow
    {
        BarcodeManager barcodeMgr;

        public ScanMsgWindow(BarcodeManager barcodeMgr)
        {
            this.barcodeMgr = barcodeMgr;
        }

        protected override void WndProc(ref Message m)
        {
            switch ((uint)m.Msg)
            {
                case Scanner.WM_SCANMSG:
                    barcodeMgr.GetBarcode(m.WParam);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }
    }
}
